﻿using HML.Design;
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace HML
{
    /// <summary>
    /// 步骤流程控件
    /// </summary>
    [Description("步骤流程控件")]
    [DefaultProperty("Items")]
    [DefaultEvent("ActiveIndexChanged")]
    [ToolboxItem(true)]
    [TypeConverter(typeof(PropertyOrderConverter))]
    [Designer(typeof(ProcedureDesigner))]
    [ToolboxBitmap(typeof(Procedure), "Controls.Procedure.Procedure.bmp")]
    public class Procedure : DpiControl
    {
        #region 新增事件

        private static readonly object EventActiveIndexChanged = new object();
        /// <summary>
        /// 已激活到的流程索引更改事件
        /// </summary>
        [Description("已激活到的流程索引更改事件")]
        public event EventHandler ActiveIndexChanged
        {
            add { Events.AddHandler(EventActiveIndexChanged, value); }
            remove { Events.RemoveHandler(EventActiveIndexChanged, value); }
        }

        #endregion

        #region 停用事件

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event KeyEventHandler KeyDown
        {
            add { base.KeyDown += value; }
            remove { base.KeyDown -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event KeyEventHandler KeyUp
        {
            add { base.KeyUp += value; }
            remove { base.KeyUp -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event KeyPressEventHandler KeyPress
        {
            add { base.KeyPress += value; }
            remove { base.KeyPress -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event PreviewKeyDownEventHandler PreviewKeyDown
        {
            add { base.PreviewKeyDown += value; }
            remove { base.PreviewKeyDown -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler TabIndexChanged
        {
            add { base.TabIndexChanged += value; }
            remove { base.TabIndexChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler TabStopChanged
        {
            add { base.TabStopChanged += value; }
            remove { base.TabStopChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler TextChanged
        {
            add { base.TextChanged += value; }
            remove { base.TextChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler FontChanged
        {
            add { base.FontChanged += value; }
            remove { base.FontChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler ForeColorChanged
        {
            add { base.ForeColorChanged += value; }
            remove { base.ForeColorChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler RightToLeftChanged
        {
            add { base.RightToLeftChanged += value; }
            remove { base.RightToLeftChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler ImeModeChanged
        {
            add { base.ImeModeChanged += value; }
            remove { base.ImeModeChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler BackgroundImageChanged
        {
            add { base.BackgroundImageChanged += value; }
            remove { base.BackgroundImageChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler BackgroundImageLayoutChanged
        {
            add { base.BackgroundImageLayoutChanged += value; }
            remove { base.BackgroundImageLayoutChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler Click
        {
            add { base.Click += value; }
            remove { base.Click -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler DoubleClick
        {
            add { base.DoubleClick += value; }
            remove { base.DoubleClick -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event MouseEventHandler MouseClick
        {
            add { base.MouseClick += value; }
            remove { base.MouseClick -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event MouseEventHandler MouseDoubleClick
        {
            add { base.MouseDoubleClick += value; }
            remove { base.MouseDoubleClick -= value; }
        }
        #endregion

        #region 新增属性

        private ProcedureOrientations orientation = ProcedureOrientations.HorizontalBottom;
        /// <summary>
        /// 流程节点方向位置
        /// </summary>
        [Description("流程节点方向位置")]
        [Category("杂项_流程")]
        [PropertyOrder(-200)]
        [DefaultValue(ProcedureOrientations.HorizontalBottom)]
        public ProcedureOrientations Orientation
        {
            get { return this.orientation; }
            set
            {
                if (this.orientation == value)
                    return;

                this.orientation = value;
                this.InitializeProcedureRectangle();
                this.Invalidate();
            }
        }

        private int activeIndex = -1;
        /// <summary>
        /// 已激活到的流程节点索引
        /// </summary>
        [Description("已激活到的流程节点索引")]
        [Category("杂项_流程")]
        [Browsable(false)]
        [PropertyOrder(-198)]
        [DefaultValue(-1)]
        public int ActiveIndex
        {
            get { return this.activeIndex; }
            set
            {
                if (this.activeIndex == value || value < -1 || value >= Items.Count)
                    return;

                this.activeIndex = value;
                this.Invalidate();

                this.OnActiveIndexChanged(EventArgs.Empty);
            }
        }

        private ProcedureItemCollection procedureItemCollection;
        /// <summary>
        /// 流程节点集合
        /// </summary>
        [Description("流程节点集合")]
        [Category("杂项_流程")]
        [PropertyOrder(-186)]
        [DefaultValue(null)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public ProcedureItemCollection Items
        {
            get
            {
                if (this.procedureItemCollection == null)
                    this.procedureItemCollection = new ProcedureItemCollection(this);
                return this.procedureItemCollection;
            }
        }

        private int flowSize = 22;
        /// <summary>
        /// 流程节点Size
        /// </summary>
        [Description("流程节点Size")]
        [Category("杂项_流程")]
        [PropertyOrder(-184)]
        [DefaultValue(22)]
        public int FlowSize
        {
            get { return this.flowSize; }
            set
            {
                if (this.flowSize == value || value <= 0)
                    return;

                this.flowSize = value;
                this.InitializeProcedureRectangle();
                this.Invalidate();
            }
        }

        private Size flowLineSize = new Size(60, 2);
        /// <summary>
        /// 流程节点间隔线Size
        /// </summary>
        [Description("流程节点间隔线Size")]
        [Category("杂项_流程")]
        [PropertyOrder(-180)]
        [DefaultValue(typeof(Size), "60,2")]
        public Size FlowLineSize
        {
            get { return this.flowLineSize; }
            set
            {
                if (this.flowLineSize == value || value.Width <= 0 || value.Height <= 0)
                    return;

                this.flowLineSize = value;
                this.InitializeProcedureRectangle();
                this.Invalidate();
            }
        }

        private Color flowLineNormalColor = Color.FromArgb(110, 153, 153);
        /// <summary>
        /// 流程节点间隔线颜色（正常）
        /// </summary>
        [Browsable(true)]
        [Description("流程节点间隔线颜色（正常）")]
        [Category("杂项_流程")]
        [PropertyOrder(-176)]
        [DefaultValue(typeof(Color), "110, 153, 153")]
        public Color FlowLineNormalColor
        {
            get { return this.flowLineNormalColor; }
            set
            {
                if (this.flowLineNormalColor == value)
                    return;

                this.flowLineNormalColor = value;
                this.Invalidate();
            }
        }

        private Color flowLineActiveColor = Color.FromArgb(110, 153, 153);
        /// <summary>
        /// 流程节点间隔线颜色（已激活）
        /// </summary>
        [Browsable(true)]
        [Description("流程节点间隔线颜色（已激活）")]
        [Category("杂项_流程")]
        [PropertyOrder(-174)]
        [DefaultValue(typeof(Color), "110, 153, 153")]
        public Color FlowLineActiveColor
        {
            get { return this.flowLineActiveColor; }
            set
            {
                if (this.flowLineActiveColor == value)
                    return;

                this.flowLineActiveColor = value;
                this.Invalidate();
            }
        }

        private Color flowBackNormalColor = Color.FromArgb(153, 204, 204);
        /// <summary>
        /// 流程节点背景颜色（正常）
        /// </summary>
        [Browsable(true)]
        [Description("流程节点背景颜色（正常）")]
        [Category("杂项_流程")]
        [PropertyOrder(-170)]
        [DefaultValue(typeof(Color), "153, 204, 204")]
        public Color FlowBackNormalColor
        {
            get { return this.flowBackNormalColor; }
            set
            {
                if (this.flowBackNormalColor == value)
                    return;

                this.flowBackNormalColor = value;
                this.Invalidate();
            }
        }


        private Color flowBackActiveColor = Color.FromArgb(110, 153, 153);
        /// <summary>
        /// 流程节点背景颜色（已激活）
        /// </summary>
        [Browsable(true)]
        [Description("流程节点背景颜色（已激活）")]
        [Category("杂项_流程")]
        [PropertyOrder(-168)]
        [DefaultValue(typeof(Color), "110, 153, 153")]
        public Color FlowBackActiveColor
        {
            get { return this.flowBackActiveColor; }
            set
            {
                if (this.flowBackActiveColor == value)
                    return;

                this.flowBackActiveColor = value;
                this.Invalidate();
            }
        }

        private bool flowIndexVisible = true;
        /// <summary>
        /// 是否显示流程节点索引
        /// </summary>
        [Description("是否显示流程节点索引")]
        [Category("杂项_流程")]
        [PropertyOrder(-164)]
        [DefaultValue(true)]
        public bool FlowIndexVisible
        {
            get { return this.flowIndexVisible; }
            set
            {
                if (this.flowIndexVisible == value)
                    return;

                this.flowIndexVisible = value;
                this.Invalidate();
            }
        }

        private Color flowIndexNormalColor = Color.White;
        /// <summary>
        /// 流程节点索引颜色（正常）
        /// </summary>
        [Browsable(true)]
        [Description("流程节点索引颜色（正常）")]
        [Category("杂项_流程")]
        [PropertyOrder(-162)]
        [DefaultValue(typeof(Color), "White")]
        public Color FlowIndexNormalColor
        {
            get { return this.flowIndexNormalColor; }
            set
            {
                if (this.flowIndexNormalColor == value)
                    return;

                this.flowIndexNormalColor = value;
                this.Invalidate();
            }
        }

        private Color flowIndexActiveColor = Color.White;
        /// <summary>
        /// 流程节点索引颜色（已激活）
        /// </summary>
        [Browsable(true)]
        [Description("流程节点索引颜色（已激活）")]
        [Category("杂项_流程")]
        [PropertyOrder(-160)]
        [DefaultValue(typeof(Color), "White")]
        public Color FlowIndexActiveColor
        {
            get { return this.flowIndexActiveColor; }
            set
            {
                if (this.flowIndexActiveColor == value)
                    return;

                this.flowIndexActiveColor = value;
                this.Invalidate();
            }
        }

        private int flowTextOffset = 5;
        /// <summary>
        /// 流程节点文本间距偏移量
        /// </summary>
        [Description("流程节点文本间距偏移量")]
        [Category("杂项_流程")]
        [PropertyOrder(-158)]
        [DefaultValue(5)]
        public int FlowTextOffset
        {
            get { return this.flowTextOffset; }
            set
            {
                if (this.flowTextOffset == value)
                    return;

                this.flowTextOffset = value;
                this.Invalidate();
            }
        }

        private Font flowTextFont = (Font)Control.DefaultFont.Clone();
        /// <summary>
        /// 流程节点文本字体
        /// </summary>
        [Description("流程节点文本字体")]
        [Category("杂项_流程")]
        [PropertyOrder(-156)]
        [DefaultValue(typeof(Font), "宋体,9pt")]
        public Font FlowTextFont
        {
            get { return this.flowTextFont; }
            set
            {
                if (this.flowTextFont == value)
                    return;

                this.flowTextFont = value;
                this.InitializeProcedureRectangle();
                this.Invalidate();
            }
        }

        private Color flowTextColor = Color.FromArgb(110, 153, 153);
        /// <summary>
        /// 流程节点文本颜色
        /// </summary>
        [Description("流程节点文本颜色")]
        [Category("杂项_流程")]
        [PropertyOrder(-154)]
        [DefaultValue(typeof(Color), "110, 153, 153")]
        public Color FlowTextColor
        {
            get { return this.flowTextColor; }
            set
            {
                if (this.flowTextColor == value)
                    return;

                this.flowTextColor = value;
                this.Invalidate();
            }
        }

        private bool tipVisible = false;
        /// <summary>
        /// 是否显示提示信息
        /// </summary>
        [Description("是否显示提示信息")]
        [Category("杂项_提示信息")]
        [PropertyOrder(-150)]
        [DefaultValue(false)]
        public bool TipVisible
        {
            get { return this.tipVisible; }
            set
            {
                if (this.tipVisible == value)
                    return;

                this.tipVisible = value;
                if (!this.tipVisible && this.tooltip != null)
                {
                    this.tooltip.Hide(this);
                    this.tooltip.Dispose();
                    this.tooltip = null;
                }
            }
        }

        private Size tipMaxSize = new Size(400, 0);
        /// <summary>
        /// 提示信息最大Size
        /// </summary>
        [Description("提示信息最大Size")]
        [Category("杂项_提示信息")]
        [PropertyOrder(-148)]
        [DefaultValue(typeof(Size), "400, 0")]
        [RefreshProperties(RefreshProperties.All)]
        public Size TipMaxSize
        {
            get { return this.tipMaxSize; }
            set
            {
                if (this.tipMaxSize == value)
                    return;

                this.tipMaxSize = value;

                if (this.tipMinSize.Width != 0 && this.tipMaxSize.Width != 0 && this.tipMinSize.Width > this.tipMaxSize.Width)
                {
                    this.tipMinSize.Width = this.tipMaxSize.Width;
                }
                if (this.tipMinSize.Height != 0 && this.tipMaxSize.Height != 0 && this.tipMinSize.Height > this.tipMaxSize.Height)
                {
                    this.tipMinSize.Height = this.tipMaxSize.Height;
                }
            }
        }

        private Size tipMinSize = new Size(30, 10);
        /// <summary>
        /// 提示信息最小Size
        /// </summary>
        [Description("提示信息最小Size")]
        [Category("杂项_提示信息")]
        [PropertyOrder(-148)]
        [DefaultValue(typeof(Size), "30, 10")]
        [RefreshProperties( RefreshProperties.All)]
        public Size TipMinSize
        {
            get { return this.tipMinSize; }
            set
            {
                if (this.tipMinSize == value)
                    return;

                this.tipMinSize = value;

                if (this.tipMaxSize.Width != 0 && this.tipMinSize.Width != 0 && this.tipMaxSize.Width < this.tipMinSize.Width)
                {
                    this.tipMaxSize.Width = this.tipMinSize.Width;
                }
                if (this.tipMaxSize.Height != 0 && this.tipMinSize.Height != 0 && this.tipMaxSize.Height < this.tipMinSize.Height)
                {
                    this.tipMaxSize.Height = this.tipMinSize.Height;
                }
            }
        }

        private Color tipBorderColor = Color.FromArgb(153, 204, 204);
        /// <summary>
        /// 提示信息背景颜色
        /// </summary>
        [Description("提示信息背景颜色")]
        [Category("杂项_提示信息")]
        [PropertyOrder(-146)]
        [DefaultValue(typeof(Color), "153, 204, 204")]
        public Color TipBorderColor
        {
            get { return this.tipBorderColor; }
            set
            {
                if (this.tipBorderColor == value)
                    return;

                this.tipBorderColor = value;
                if (this.tooltip != null)
                    this.tooltip.BorderColor = value;
            }
        }

        private Color tipBackColor = Color.FromArgb(153, 204, 204);
        /// <summary>
        /// 提示信息背景颜色
        /// </summary>
        [Description("提示信息背景颜色")]
        [Category("杂项_提示信息")]
        [PropertyOrder(-144)]
        [DefaultValue(typeof(Color), "153, 204, 204")]
        public Color TipBackColor
        {
            get { return this.tipBackColor; }
            set
            {
                if (this.tipBackColor == value)
                    return;

                this.tipBackColor = value;
                if (this.tooltip != null)
                    this.tooltip.BackColor = value;
            }
        }

        private Color tipTextColor = Color.White;
        /// <summary>
        /// 提示信息文本颜色
        /// </summary>
        [Description("提示信息文本颜色")]
        [Category("杂项_提示信息")]
        [PropertyOrder(-140)]
        [DefaultValue(typeof(Color), "White")]
        public Color TipTextColor
        {
            get { return this.tipTextColor; }
            set
            {
                if (this.tipTextColor == value)
                    return;

                this.tipTextColor = value;
                if (this.tooltip != null)
                    this.tooltip.ForeColor = value;
            }
        }

        private Font tipTextFont = (Font)Control.DefaultFont.Clone();
        /// <summary>
        /// 提示信息文本字体
        /// </summary>
        [Description("提示信息文本字体")]
        [Category("杂项_提示信息")]
        [PropertyOrder(-138)]
        [DefaultValue(typeof(Font), "宋体,9pt")]
        public Font TipTextFont
        {
            get { return this.tipTextFont; }
            set
            {
                if (this.tipTextFont == value)
                    return;

                this.tipTextFont = value;
                if (this.tooltip != null)
                    this.tooltip.Font = value;
            }
        }

        #endregion

        #region 重写属性

        protected override Padding DefaultPadding
        {
            get { return new Padding(10, 10, 10, 10); }
        }

        [DefaultValue(typeof(Padding), "10,10,10,10")]
        public new Padding Padding
        {
            get { return base.Padding; }
            set
            {
                if (base.Padding == value)
                    return;

                base.Padding = value;
                this.InitializeProcedureRectangle();
                this.Invalidate();
            }
        }

        protected override Size DefaultSize
        {
            get { return new Size(220, 60); }
        }

        [DefaultValue(typeof(Color), "Transparent")]
        public override Color BackColor
        {
            get { return base.BackColor; }
            set { base.BackColor = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        protected override ImeMode DefaultImeMode
        {
            get { return ImeMode.Disable; }
        }

        #endregion

        #region 停用属性

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new int TabIndex
        {
            get { return base.TabIndex; }
            set { base.TabIndex = value; }
        }

        [DefaultValue(false)]
        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new bool TabStop
        {
            get { return base.TabStop; }
            set { base.TabStop = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override string Text
        {
            get { return base.Text; }
            set { base.Text = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public override Color ForeColor
        {
            get { return base.ForeColor; }
            set { base.ForeColor = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public override Font Font
        {
            get { return base.Font; }
            set { base.Font = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public override RightToLeft RightToLeft
        {
            get { return base.RightToLeft; }
            set { base.RightToLeft = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new ImeMode ImeMode
        {
            get { return base.ImeMode; }
            set { base.ImeMode = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public override Image BackgroundImage
        {
            get { return base.BackgroundImage; }
            set { base.BackgroundImage = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public override ImageLayout BackgroundImageLayout
        {
            get { return base.BackgroundImageLayout; }
            set { base.BackgroundImageLayout = value; }
        }

        #endregion

        #region 字段

        /// <summary>
        ///  提示信息
        /// </summary>
        private ToolTipPlus tooltip;
        /// <summary>
        /// 当前提示信息索引
        /// </summary>
        private int currentTipIndex = -2;

        /// <summary>
        /// 文本格式
        /// </summary>
        protected static StringFormat text_sf = new StringFormat() { FormatFlags = StringFormatFlags.NoWrap, Alignment = StringAlignment.Center, Trimming = StringTrimming.None };

        #endregion

        public Procedure()
        {
            SetStyle(ControlStyles.UserPaint, true);
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            SetStyle(ControlStyles.ResizeRedraw, true);
            SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            SetStyle(ControlStyles.StandardClick, false);
            SetStyle(ControlStyles.StandardDoubleClick, false);

            this.SuspendLayout();
            this.BackColor = Color.Transparent;
            this.TabStop = false;
            this.ResumeLayout();
        }

        #region 重写

        protected override void OnScaleDpiChangedInitialize()
        {
            this.InitializeProcedureRectangle();
            this.Invalidate();
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            Graphics g = e.Graphics;
            g.SmoothingMode = SmoothingMode.AntiAlias;

            Padding scale_padding = new Padding((int)(this.Padding.Left * this.ScaleDpi), (int)(this.Padding.Top * this.ScaleDpi), (int)(this.Padding.Right * this.ScaleDpi), (int)(this.Padding.Bottom * this.ScaleDpi));
            Size scale_flowLineSize = new Size((int)Math.Ceiling(this.FlowLineSize.Width * this.ScaleDpi), (int)Math.Ceiling(this.FlowLineSize.Height * this.ScaleDpi));
            int scale_text_flowTextOffset = (int)Math.Ceiling(this.FlowTextOffset * this.ScaleDpi);
            RectangleF scale_rectf = new Rectangle(this.ClientRectangle.Left + scale_padding.Left, this.ClientRectangle.Top + scale_padding.Top, this.ClientRectangle.Width - scale_padding.Left - scale_padding.Right, this.ClientRectangle.Height - scale_padding.Top - scale_padding.Bottom);

            Pen flow_line_pen = new Pen(Color.White, scale_flowLineSize.Height);
            SolidBrush flow_back_sb = new SolidBrush(Color.White);
            SolidBrush flow_text_sb = new SolidBrush(this.FlowTextColor);

            for (int i = 0; i < this.Items.Count; i++)
            {
                ProcedureItem current_item = this.Items[i];

                // 流程节点背景
                flow_back_sb.Color = (i <= this.ActiveIndex - 1) ? this.FlowBackActiveColor : this.FlowBackNormalColor;
                g.FillEllipse(flow_back_sb, current_item.RectF);

                // 流程节点边框
                flow_line_pen.Color = (i <= this.ActiveIndex - 1) ? this.FlowLineActiveColor : this.FlowLineNormalColor;
                g.DrawEllipse(flow_line_pen, ControlHelper.TransformRectangleF(current_item.RectF, scale_flowLineSize.Height));

                // 流程节点间隔线
                if (i > 0 && i < this.Items.Count)
                {
                    ProcedureItem prev_item = this.Items[i - 1];
                    PointF flow_line_strat_point = new PointF(prev_item.RectF.Right - scale_flowLineSize.Height + (float)scale_flowLineSize.Height / 2f, prev_item.RectF.Y + current_item.RectF.Height / 2f);
                    PointF flow_line_end_point = new PointF(current_item.RectF.X + scale_flowLineSize.Height - (float)scale_flowLineSize.Height / 2f, current_item.RectF.Y + current_item.RectF.Height / 2);
                    if (this.Orientation == ProcedureOrientations.VerticalLeft || this.Orientation == ProcedureOrientations.VerticalRight)
                    {
                        flow_line_strat_point = new PointF(prev_item.RectF.X + current_item.RectF.Width / 2f, prev_item.RectF.Bottom - scale_flowLineSize.Height + (float)scale_flowLineSize.Height / 2);
                        flow_line_end_point = new PointF(current_item.RectF.X + current_item.RectF.Width / 2f, current_item.RectF.Y + scale_flowLineSize.Height - (float)scale_flowLineSize.Height / 2);
                    }
                    g.DrawLine(flow_line_pen, flow_line_strat_point, flow_line_end_point);
                }

                // 流程节点文本
                Size text_size = g.MeasureString(current_item.Text, this.FlowTextFont, new SizeF(), StringFormat.GenericTypographic).ToSize();
                PointF text_point = PointF.Empty;
                if (this.Orientation == ProcedureOrientations.HorizontalBottom)
                {
                    text_point = new PointF(current_item.RectF.X + (current_item.RectF.Width - text_size.Width) / 2f, current_item.RectF.Y - scale_text_flowTextOffset - text_size.Height);
                }
                if (this.Orientation == ProcedureOrientations.HorizontalTop)
                {
                    text_point = new PointF(current_item.RectF.X + (current_item.RectF.Width - text_size.Width) / 2f, current_item.RectF.Bottom + scale_text_flowTextOffset);
                }
                else if (this.Orientation == ProcedureOrientations.VerticalLeft)
                {
                    text_point = new PointF(current_item.RectF.Right + scale_text_flowTextOffset, current_item.RectF.Y + (current_item.RectF.Height - text_size.Height) / 2f);
                }
                else if (this.Orientation == ProcedureOrientations.VerticalRight)
                {
                    text_point = new PointF(current_item.RectF.X - scale_text_flowTextOffset - text_size.Width, current_item.RectF.Y + (current_item.RectF.Height - text_size.Height) / 2f);
                }

                g.DrawString(current_item.Text, this.FlowTextFont, flow_text_sb, text_point, StringFormat.GenericTypographic);
            }

            flow_line_pen.Dispose();
            flow_back_sb.Dispose();
            flow_text_sb.Dispose();

            //流程节点索引
            if (this.FlowIndexVisible)
            {
                int scale_flow_radius = (int)Math.Ceiling(this.FlowSize * this.ScaleDpi / 2f);
                float flow_index_font_height = scale_flow_radius * 2 * 8f / 10f;

                Font flow_index_font = new Font("宋体", SystemFonts.DefaultFont.Size * (flow_index_font_height / SystemFonts.DefaultFont.Height));
                SolidBrush flow_index_sb = new SolidBrush(Color.White);
                for (int i = 0; i < this.Items.Count; i++)
                {
                    flow_index_sb.Color = (i <= this.ActiveIndex - 1) ? this.FlowIndexActiveColor : this.FlowIndexNormalColor;
                    Size flow_index_size = g.MeasureString((i + 1).ToString(), flow_index_font, int.MaxValue, StringFormat.GenericTypographic).ToSize();
                    g.DrawString((i + 1).ToString(), flow_index_font, flow_index_sb, new PointF(this.Items[i].RectF.X + (this.Items[i].RectF.Width - flow_index_size.Width) / 2, this.Items[i].RectF.Y + (this.Items[i].RectF.Height - flow_index_size.Height) / 2), StringFormat.GenericTypographic);
                }
                flow_index_font.Dispose();
                flow_index_sb.Dispose();
            }

        }

        protected override void OnLeave(EventArgs e)
        {
            base.OnLeave(e);

            if (this.currentTipIndex > -2)
            {
                this.HideTip();
            }
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            int index = this.GetSelectedIndex(this.PointToClient(Control.MousePosition));
            if (index > -1)
            {
                if (this.TipVisible && this.currentTipIndex != index)
                {
                    this.ShowTip(index);
                }
            }
            else
            {
                if (this.currentTipIndex > -2)
                {
                    this.HideTip();
                }
            }
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            base.OnMouseLeave(e);

            if (this.currentTipIndex > -2)
            {
                this.HideTip();
            }
        }

        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);

            this.InitializeProcedureRectangle();
            this.Invalidate();
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (this.tooltip != null)
                {
                    this.tooltip.Dispose();
                    this.tooltip = null;
                }
                for (int i = 0; i < this.Items.Count; i++)
                {
                    if (this.Items[i].GP != null)
                    {
                        this.Items[i].GP.Dispose();
                        this.Items[i].GP = null;
                    }
                }
            }
            base.Dispose(disposing);
        }

        #endregion

        #region 虚方法

        protected virtual void OnActiveIndexChanged(EventArgs e)
        {
            EventHandler handler = Events[EventActiveIndexChanged] as EventHandler;
            if (handler != null)
            {
                handler(this, e);
            }
        }

        #endregion

        #region 私有方法

        /// <summary>
        /// 初始化流程节点rect
        /// </summary>
        /// <param name="item"></param>
        internal void InitializeProcedureRectangle()
        {
            for (int i = 0; i < this.Items.Count; i++)
            {
                this.InitializeProcedureRectangle(this.Items[i]);
            }
        }

        /// <summary>
        /// 初始化流程节点rect
        /// </summary>
        /// <param name="item"></param>
        internal void InitializeProcedureRectangle(ProcedureItem item)
        {
            Padding scale_padding = new Padding((int)(this.Padding.Left * this.ScaleDpi), (int)(this.Padding.Top * this.ScaleDpi), (int)(this.Padding.Right * this.ScaleDpi), (int)(this.Padding.Bottom * this.ScaleDpi));
            Size scale_flowLineSize = new Size((int)Math.Ceiling(this.FlowLineSize.Width * this.ScaleDpi), (int)Math.Ceiling(this.FlowLineSize.Height * this.ScaleDpi));
            int scale_flow_radius = (int)Math.Ceiling(this.FlowSize * this.ScaleDpi / 2f);
            RectangleF scale_rectf = new Rectangle(this.ClientRectangle.Left + scale_padding.Left, this.ClientRectangle.Top + scale_padding.Top, this.ClientRectangle.Width - scale_padding.Left - scale_padding.Right, this.ClientRectangle.Height - scale_padding.Top - scale_padding.Bottom);

            int index = this.Items.IndexOf(item);
            if (this.Orientation == ProcedureOrientations.HorizontalBottom)
            {
                float x = scale_rectf.Left + index * (scale_flow_radius * 2f + scale_flowLineSize.Width);
                float y = scale_rectf.Bottom - scale_flow_radius * 2;
                item.RectF = new RectangleF(x, y, scale_flow_radius * 2, scale_flow_radius * 2);
            }
            else if (this.Orientation == ProcedureOrientations.HorizontalTop)
            {
                float x = scale_rectf.Left + index * (scale_flow_radius * 2f + scale_flowLineSize.Width);
                float y = scale_rectf.Top;
                item.RectF = new RectangleF(x, y, scale_flow_radius * 2, scale_flow_radius * 2);
            }
            else if (this.Orientation == ProcedureOrientations.VerticalLeft)
            {
                float x = scale_rectf.Left;
                float y = scale_rectf.Top + index * (scale_flow_radius * 2f + scale_flowLineSize.Width);
                item.RectF = new RectangleF(x, y, scale_flow_radius * 2, scale_flow_radius * 2);
            }
            else if (this.Orientation == ProcedureOrientations.VerticalRight)
            {
                float x = scale_rectf.Right - scale_flow_radius * 2;
                float y = scale_rectf.Top + index * (scale_flow_radius * 2f + scale_flowLineSize.Width);
                item.RectF = new RectangleF(x, y, scale_flow_radius * 2, scale_flow_radius * 2);
            }
            if (item.GP == null)
            {
                GraphicsPath gp = new GraphicsPath();
                gp.AddEllipse(item.RectF);
                item.GP = gp;
            }
            else
            {
                item.GP.Reset();
                item.GP.AddEllipse(item.RectF);
            }
        }

        /// <summary>
        /// 获取鼠标进入的流程节点索引
        /// </summary>
        /// <param name="point">当前鼠标坐标</param>
        /// <returns></returns>
        private int GetSelectedIndex(Point point)
        {
            for (int i = 0; i < this.Items.Count; i++)
            {
                if (this.Items[i].GP != null && this.Items[i].GP.IsVisible(point))
                {
                    return i;
                }
            }
            return -1;
        }

        /// <summary>
        /// 显示指定索引流程提示信息
        /// </summary>
        /// <param name="index">指定流程索引</param>
        private void ShowTip(int index)
        {
            if (this.tooltip == null)
            {
                this.tooltip = new ToolTipPlus();
                this.tooltip.TitleVisible = false;
                this.tooltip.BorderVisible = true;
                this.tooltip.UseAnimation = false;

                this.tooltip.BorderColor = this.TipBorderColor;
                this.tooltip.BackColor = this.TipBackColor;
                this.tooltip.ForeColor = this.TipTextColor;
                this.tooltip.Font = this.TipTextFont;
            }
            this.tooltip.MinSize = this.TipMinSize;
            this.tooltip.MaxSize = this.TipMaxSize;

            ToolTipPlusAnchors anchor = ToolTipPlusAnchors.TopCenter;
            if (this.Orientation == ProcedureOrientations.HorizontalBottom)
            {
                anchor = ToolTipPlusAnchors.BottomCenter;
            }
            else if (this.Orientation == ProcedureOrientations.VerticalLeft)
            {
                anchor = ToolTipPlusAnchors.LeftCenter;
            }
            else if (this.Orientation == ProcedureOrientations.VerticalRight)
            {
                anchor = ToolTipPlusAnchors.RightCenter;
            }
            Rectangle rect = new Rectangle((int)this.Items[index].RectF.X, (int)this.Items[index].RectF.Y, (int)this.Items[index].RectF.Width, (int)this.Items[index].RectF.Height);
            this.tooltip.ToolTipTitle = this.Items[index].Text;
            string str = this.Items[index].TipText == String.Empty ? " " : this.Items[index].TipText;
            this.tooltip.Show(str, this, rect, anchor);
            this.currentTipIndex = index;
        }

        /// <summary>
        /// 隐藏提示
        /// </summary>
        private void HideTip()
        {
            this.tooltip.Hide(this);
            this.currentTipIndex = -2;
        }

        #endregion

    }
}
